Function.RegisterNamespace("Test.System.Script");

[Fixture]
Test.System.Script.ObjectSerializer=function(){
    [Fixture]
    function Deserialize(){
        [Fact]
        function ReturnsNullIfSourceIsOmitted(){
            var actual=new System.Script.ObjectSerializer().Deserialize();

            Assert.Null(actual);
        }

        [Fact]
        function ReturnsNullIfSourceIsUndefined(){
            var actual=new System.Script.ObjectSerializer().Deserialize(undefined);

            Assert.Null(actual);
        }
        
        [Fact]
        function ReturnsNullIfSourceIsNull(){
            var actual=new System.Script.ObjectSerializer().Deserialize(null);

            Assert.Null(actual);
        }
        
        [Fact]
        function ThrowsIfSourceContainsUnquotedIdentifier(){
            var target="{target:\"\"}";
            var expected=String.Format("System.Script.ObjectSerializer.Deserialize: 'source' is invalid or unsafe object notation.\nSource: {0}",target);

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ThrowsIfSourceContainsUnquotedValue(){
            var target="{\"target\":expected}";
            var expected=String.Format("System.Script.ObjectSerializer.Deserialize: 'source' is invalid or unsafe object notation.\nSource: {0}",target);

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfSourceContainsValueQuotedInSingleQuotes(){
            var target="{\"target\":''}";
            var expected=String.Format("System.Script.ObjectSerializer.Deserialize: 'source' is invalid or unsafe object notation.\nSource: {0}",target);

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ThrowsIfSourceContainsUnquotedFunctionValue(){
            var target="{\"target\":function(){}}";
            var expected=String.Format("System.Script.ObjectSerializer.Deserialize: 'source' is invalid or unsafe object notation.\nSource: {0}",target);

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfSourceContainsNewArrayConstructorValue(){
            var target="{\"target\":new Array()}";
            var expected=String.Format("System.Script.ObjectSerializer.Deserialize: 'source' is invalid or unsafe object notation.\nSource: {0}",target);

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfSourceContainsNewBooleanConstructorValue(){
            var target="{\"target\":new Boolean()}";
            var expected=String.Format("System.Script.ObjectSerializer.Deserialize: 'source' is invalid or unsafe object notation.\nSource: {0}",target);

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ThrowsIfSourceContainsNewErrorConstructorValue(){
            var target="{\"target\":new Error()}";
            var expected=String.Format("System.Script.ObjectSerializer.Deserialize: 'source' is invalid or unsafe object notation.\nSource: {0}",target);

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfSourceContainsNewFunctionConstructorValue(){
            var target="{\"target\":new Function()}";
            var expected=String.Format("System.Script.ObjectSerializer.Deserialize: 'source' is invalid or unsafe object notation.\nSource: {0}",target);

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfSourceContainsNewNumberConstructorValue(){
            var target="{\"target\":new Number()}";
            var expected=String.Format("System.Script.ObjectSerializer.Deserialize: 'source' is invalid or unsafe object notation.\nSource: {0}",target);

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ThrowsIfSourceContainsNewObjectConstructorValue(){
            var target="{\"target\":new Object()}";
            var expected=String.Format("System.Script.ObjectSerializer.Deserialize: 'source' is invalid or unsafe object notation.\nSource: {0}",target);

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ThrowsIfSourceContainsNewStringConstructorValue(){
            var target="{\"target\":new String()}";
            var expected=String.Format("System.Script.ObjectSerializer.Deserialize: 'source' is invalid or unsafe object notation.\nSource: {0}",target);

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ThrowsIfSourceContainsThrowAsValue(){
            var target="{\"target\":throw new Error()}";
            var expected=String.Format("System.Script.ObjectSerializer.Deserialize: 'source' is invalid or unsafe object notation.\nSource: {0}",target);

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Equal(expected,actual);
        }


        [Fact]
        function DoesNotThrowIfSourceContainsShorthandObjectValue(){
            var target="{\"target\":{}}";

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Null(actual);
        }

        [Fact]
        function DoesNotThrowIfSourceContainsShorthandArrayValue(){
            var target="{\"target\":[]}";

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Null(actual);
        }

        [Fact]
        function DoesNotThrowIfSourceContainsUnquotedBooleanFalseValue(){
            var target="{\"target\":false}";

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Null(actual);
        }

        [Fact]
        function DoesNotThrowIfSourceContainsUnquotedBooleanTrueValue(){
            var target="{\"target\":true}";

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Null(actual);
        }

        [Fact]
        function DoesNotThrowIfSourceContainsUnquotedNumberValue(){
            var target="{\"target\":1}";

            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Null(actual);
        }

        [Fact]
        function ThrowsIfEvalThrows(){
            var target="{\"target\":}";
        
            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.NotNull(actual);
        }        

        [Fact]
        function ThrowsWhatEvalThrows(){
            var target="{\"target\":}";
            var targetError=Record.Exception(function(){eval(['(',')'].join(target))});
            var expected=String.Format("System.Script.ObjectSerializer.Deserialize: unable to deserialize source.\nError: {0}.\nSource: {1}",targetError,target);
        
            var actual=Record.Exception(function(){
                new System.Script.ObjectSerializer().Deserialize(target);
            });
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ReturnsObject(){
            var target="{\"target\":\"expected\"}";
        
            var actual=new System.Script.ObjectSerializer().Deserialize(target);

            Assert.NotNull(actual);
        }

        [Fact]
        function ReturnsDeserializedObject(){
            var target="{\"target\":\"expected\"}";
            var expected={target:"expected"};
        
            var actual=new System.Script.ObjectSerializer().Deserialize(target);

            Assert.Equal(expected,actual);
        }

        [Fact]
        function SetsToStringOverrideOnDeserializedObject(){
            var target="{\"target\":\"expected\"}";
            var expected=String.prototype.toString;
        
            var actual=new System.Script.ObjectSerializer().Deserialize(target).toString;

            Assert.NotEqual(expected,actual);
        }

        [Fact]
        function ToStringOverrideReturnsSource(){
            var expected="{\"target\":\"expected\"}";
        
            var actual=new System.Script.ObjectSerializer().Deserialize(expected).toString();

            Assert.Equal(expected,actual);
        }
    }
    
    [Fixture]
    function Serialize(){
        [Fact]
        function ReturnsNullStringIfTargetIsOmitted(){
            var expected="null";

            var actual=new System.Script.ObjectSerializer().Serialize();

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsNullStringIfTargetIsUndefined(){
            var expected="null";

            var actual=new System.Script.ObjectSerializer().Serialize(undefined);

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsNullStringIfTargetIsNull(){
            var expected="null";

            var actual=new System.Script.ObjectSerializer().Serialize(null);

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsArray(){
            var expected="[]";

            var actual=new System.Script.ObjectSerializer().Serialize([]);

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsArrayOfArrays(){
            var expected="[[],[],[]]";

            var actual=new System.Script.ObjectSerializer().Serialize([[],[],[]]);

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsArrayOfBooleans(){
            var expected="[true,false,true]";

            var actual=new System.Script.ObjectSerializer().Serialize([true,false,true]);

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsArrayOfDates(){
            var expected="[\"2001/01/01T01:01:01Z\",\"2002/02/02T02:02:02Z\",\"2003/12/31T23:59:59Z\"]";
            var target=[new Date(2001,0,1,1,1,1),new Date(2002,1,2,2,2,2),new Date(2003,11,31,23,59,59)];
            Array.ForEach(target,function(date){date.setMinutes(date.getMinutes()-date.getTimezoneOffset())});

            var actual=new System.Script.ObjectSerializer().Serialize(target);

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsArrayOfErrorsConvertedToObjects(){
            var targetError=new Error();
            var targetErrorString="{";
            for(var x in targetError)targetErrorString+=String.Format("\"{0}\":{1},",x,typeof(targetError[x])=="number"?targetError[x]:String.Format("\"{0}\"",targetError[x].replace(/\\/g,"\\\\").replace(/"/g,"\\\"").replace(/\n/g,"\\n").replace(/\r/g,"\\r")));
            targetErrorString=String.TrimEnd(targetErrorString,',');
            targetErrorString+="}";
            var expected=String.Format("[{0},{0},{0}]",targetErrorString);
            var actual=new System.Script.ObjectSerializer().Serialize([targetError,targetError,targetError]);
            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsArrayOfFunctionsConvertedToEmptyStrings(){
            var expected="[\"\",\"\",\"\"]";

            var actual=new System.Script.ObjectSerializer().Serialize([function(){},function(){},function(){}]);

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsArrayOfObjects(){
            var expected="[{},{},{}]";

            var actual=new System.Script.ObjectSerializer().Serialize([{},{},{}]);

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsArrayOfNumbers(){
            var expected="[1,2,3]";

            var actual=new System.Script.ObjectSerializer().Serialize([1,2,3]);

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsArrayOfStrings(){
            var expected="[\"expected1\",\"expected2\",\"expected3\"]";

            var actual=new System.Script.ObjectSerializer().Serialize(["expected1","expected2","expected3"]);

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsArrayOfCustomObjects(){
            var expected="[{\"expected\":\"expected\"},{\"expected\":\"expected\"},{\"expected\":\"expected\"}]";
            var target=function(){
                this.expected="expected";
            }

            var actual=new System.Script.ObjectSerializer().Serialize([new target(),new target(),new target()]);

            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ReturnsBoolean(){
            var expected="true";
            
            var actual=new System.Script.ObjectSerializer().Serialize(true);

            Assert.Equal(expected,actual);
        }
/*        
        [Fact]
        function ReturnsDate(){
            var expected="\"2001/01/01T01:01:01Z\"";
            var targetDate=new Date(2001,0,1,1,1,1);
            targetDate.setMinutes(targetDate.getMinutes()-targetDate.getTimezoneOffset())
            
            var actual=new System.Script.ObjectSerializer().Serialize(targetDate);
            
            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ReturnsError(){
            var targetError=new Error();
            var targetErrorString="{";
            for(var x in targetError)targetErrorString+=String.Format("\"{0}\":{1},",x,typeof(targetError[x])=="number"?targetError[x]:String.Format("\"{0}\"",targetError[x]));            
            targetErrorString=String.TrimEnd(targetErrorString,',');
            targetErrorString+="}";
            var expected=targetErrorString;
            
            var actual=new System.Script.ObjectSerializer().Serialize(targetError);

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsFunctionAsEmptyString(){
            var expected="\"\"";
            
            var actual=new System.Script.ObjectSerializer().Serialize(function(){});

            Assert.Equal(expected,actual);
        }        
        
        [Fact]
        function ReturnsNumber(){
            var expected=1;
            
            var actual=new System.Script.ObjectSerializer().Serialize(1);

            Assert.Equal(expected,actual);
        }        
        
        [Fact]
        function ReturnsObject(){
            var expected="{}";

            var actual=new System.Script.ObjectSerializer().Serialize({});

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsObjectWithArrayProperty(){
            var expected="{\"expected\":[]}";

            var actual=new System.Script.ObjectSerializer().Serialize({expected:[]});

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsObjectWithBooleanProperty(){
            var expected="{\"expected\":true}";

            var actual=new System.Script.ObjectSerializer().Serialize({expected:true});

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsObjectWithErrorProperty(){
            var targetError=new Error();
            var targetErrorString="{";
            for(var x in targetError)targetErrorString+=String.Format("\"{0}\":{1},",x,typeof(targetError[x])=="number"?targetError[x]:String.Format("\"{0}\"",targetError[x]));            
            targetErrorString=String.TrimEnd(targetErrorString,',');
            targetErrorString+="}";
            var expected=String.Format("{\"expected\":{0}}",targetErrorString);

            var actual=new System.Script.ObjectSerializer().Serialize({expected:targetError});

            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ReturnsObjectWithFunctionProperty(){
            var expected="{\"expected\":\"\"}";

            var actual=new System.Script.ObjectSerializer().Serialize({expected:function(){}});

            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ReturnsObjectWithNumberProperty(){
            var expected="{\"expected\":1}";

            var actual=new System.Script.ObjectSerializer().Serialize({expected:1});

            Assert.Equal(expected,actual);
        }
        
        [Fact]
        function ReturnsObjectWithObjectProperty(){
            var expected="{\"expected\":{}}";

            var actual=new System.Script.ObjectSerializer().Serialize({expected:{}});

            Assert.Equal(expected,actual);
        }        

        [Fact]
        function ReturnsObjectWithStringProperty(){
            var expected="{\"expected\":\"\"}";

            var actual=new System.Script.ObjectSerializer().Serialize({expected:''});

            Assert.Equal(expected,actual);
        }

        [Fact]
        function ReturnsObjectWithCustomObjectProperty(){
            var expected="{\"expected\":{\"expected\":\"expected\"}}";
            var target=function(){
                this.expected={expected:"expected"};
            }

            var actual=new System.Script.ObjectSerializer().Serialize(new target());

            Assert.Equal(expected,actual);
        }
       
        [Fact]
        function ReturnsString(){
            var expected="\"expected\"";
            
            var actual=new System.Script.ObjectSerializer().Serialize("expected");

            Assert.Equal(expected,actual);
        }
*/
    }
}